#include "TABLED1Data.h"

#include <algorithm>
#include <cmath>

#include "DataStructure/Common/Validation.h"

using namespace SG::DataStructure::FEM;

SG::Algebra::Real_t TABLED1Data::Interpolate (SG::Algebra::Real_t t) const
{
    const auto& points = m_XYList;

    // 处理空表或单点表
    if (points.empty ())
        return 0.0;
    if (points.size () == 1)
        return points[0].m_Y;

    // 处理边界外推情况
    if (t < points.front ().m_X)
    {
        // 左边界外推，使用前两个点进行线性外推
        const auto& x1 = points[0].m_X;
        const auto& x2 = points[1].m_X;
        const auto& y1 = points[0].m_Y;
        const auto& y2 = points[1].m_Y;

        // 只允许线性外推，不考虑对数轴
        return InterpolateLinearLinear (x1, x2, y1, y2, t);
    }

    if (t > points.back ().m_X)
    {
        // 右边界外推，使用最后两个点进行线性外推
        const auto& x1 = points[points.size () - 2].m_X;
        const auto& x2 = points[points.size () - 1].m_X;
        const auto& y1 = points[points.size () - 2].m_Y;
        const auto& y2 = points[points.size () - 1].m_Y;

        // 只允许线性外推，不考虑对数轴
        return InterpolateLinearLinear (x1, x2, y1, y2, t);
    }

    // 在表格范围内插值
    for (size_t i = 0; i < points.size () - 1; ++i)
    {
        const auto& xi = points[i].m_X;
        const auto& xj = points[i + 1].m_X;

        if (t >= xi && t <= xj)
        {
            const auto& yi = points[i].m_Y;
            const auto& yj = points[i + 1].m_Y;

            // 处理不连续点：如果xi == xj（相同x值的不同y值），使用平均值
            if (std::abs (xj - xi) < 1e-12)
            {
                return (yi + yj) / 2.0;
            }

            // 根据CODEX和CODEY选择插值方法
            if (!IsXAxisLog ())
            {
                if (!IsYAxisLog ())
                {
                    // LINEAR-LINEAR
                    return InterpolateLinearLinear (xi, xj, yi, yj, t);
                }
                else
                {
                    // LINEAR-LOG
                    return InterpolateLinearLog (xi, xj, yi, yj, t);
                }
            }
            else
            {
                if (!IsYAxisLog ())
                {
                    // LOG-LINEAR
                    return InterpolateLogLinear (xi, xj, yi, yj, t);
                }
                else
                {
                    // LOG-LOG
                    return InterpolateLogLog (xi, xj, yi, yj, t);
                }
            }
        }
    }

    // 理论上不应该到达这里
    return 0.0;
}

SG::Algebra::Real_t TABLED1Data::InterpolateLinearLinear (
    SG::Algebra::Real_t xi, SG::Algebra::Real_t xj, SG::Algebra::Real_t yi, SG::Algebra::Real_t yj, SG::Algebra::Real_t t)
{
    // 标准线性插值公式
    return yi + (yj - yi) * (t - xi) / (xj - xi);
}

SG::Algebra::Real_t TABLED1Data::InterpolateLogLinear (
    SG::Algebra::Real_t xi, SG::Algebra::Real_t xj, SG::Algebra::Real_t yi, SG::Algebra::Real_t yj, SG::Algebra::Real_t t)
{
    // LOG x轴, LINEAR y轴
    // 检查对数轴的有效性
    if (xi <= 0 || xj <= 0 || t <= 0)
    {
        // 如果有非正值，回退到线性插值
        return InterpolateLinearLinear (xi, xj, yi, yj, t);
    }

    return yi * std::log (xj / t) / std::log (xj / xi) + yj * std::log (t / xi) / std::log (xj / xi);
}

SG::Algebra::Real_t TABLED1Data::InterpolateLinearLog (
    SG::Algebra::Real_t xi, SG::Algebra::Real_t xj, SG::Algebra::Real_t yi, SG::Algebra::Real_t yj, SG::Algebra::Real_t t)
{
    // LINEAR x轴, LOG y轴
    // 检查对数轴的有效性
    if (yi <= 0 || yj <= 0)
    {
        // 如果有非正值，回退到线性插值
        return InterpolateLinearLinear (xi, xj, yi, yj, t);
    }

    return std::exp (std::log (yi) * (xj - t) / (xj - xi) + std::log (yj) * (t - xi) / (xj - xi));
}

SG::Algebra::Real_t TABLED1Data::InterpolateLogLog (
    SG::Algebra::Real_t xi, SG::Algebra::Real_t xj, SG::Algebra::Real_t yi, SG::Algebra::Real_t yj, SG::Algebra::Real_t t)
{
    // LOG x轴, LOG y轴
    // 检查对数轴的有效性
    if (xi <= 0 || xj <= 0 || t <= 0 || yi <= 0 || yj <= 0)
    {
        // 如果有非正值，回退到线性插值
        return InterpolateLinearLinear (xi, xj, yi, yj, t);
    }

    return std::exp (std::log (yi) * std::log (xj / t) / std::log (xj / xi) + std::log (yj) * std::log (t / xi) / std::log (xj / xi));
}

bool SG::DataStructure::FEM::operator== (const TABLED1Data::XYData& val1, const TABLED1Data::XYData& val2)
{
    FIELD_COMPARE (m_X)
    FIELD_COMPARE (m_Y)
    return true;
}

bool SG::DataStructure::FEM::operator== (const TABLED1Data& val1, const TABLED1Data& val2)
{
    FIELD_COMPARE (m_id)
    FIELD_COMPARE (m_CODEX)
    FIELD_COMPARE (m_CODEY)
    FIELD_COMPARE (m_domainId)
    FIELD_COMPARE (m_XYList)
    return true;
}